package com.ruoyi.caiwu.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.caiwu.domain.*;
import com.ruoyi.caiwu.dto.CheckBatchConfirmRequestDto;
import com.ruoyi.caiwu.dto.CheckBatchConfirmResponseDto;
import com.ruoyi.caiwu.entity.CwCheckBatchDetailEntity;
import com.ruoyi.caiwu.entity.CwCheckBatchEntity;
import com.ruoyi.caiwu.enums.*;
import com.ruoyi.caiwu.mapper.CwCheckBatchDetailMapper;
import com.ruoyi.caiwu.service.*;
import com.ruoyi.caiwu.mapper.CwCheckBatchMapper;
import com.ruoyi.common.core.exception.BusinessException;
import com.ruoyi.common.security.service.TokenService;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
* @author 86182
* @description 针对表【t_cw_check_batch(对账批次表)】的数据库操作Service实现
* @createDate 2023-05-03 18:38:59
*/
@Log
@Service
public class CwCheckBatchServiceImpl extends ServiceImpl<CwCheckBatchMapper, CwCheckBatch>
    implements CwCheckBatchService{

    @Autowired
    TokenService tokenService;

    @Autowired
    CwCheckBatchDetailService cwCheckBatchDetailService;

    @Autowired
    CwPayOrderService cwPayOrderService;

    @Autowired
    CwClearingService clearingService;

    @Autowired
    CwCheckBatchDetailMapper cwCheckBatchDetailMapper;

    @Autowired
    CwPayOrderDetailService cwPayOrderDetailService;

    // 连接拉卡拉数据和平台数据的连接符（对账明细里面显示用）
    private static final String CHECKDETAILCONNECTSTR = "/";

    @Override
    public IPage<CwCheckBatch> selectCheckBatch(Page page, CwCheckBatchVo cwCheckBatchVo) {
        return this.baseMapper.selectCheckBatch(page,cwCheckBatchVo);
    }

    @Override
    public void processCheckDifResult(Long checkBatchDetailId, Integer processState) {
        log.info("processCheckDifResult对账差异的差错处理 Start...");
        // 数据库状态检查，防止重复处理
        CwCheckBatchDetail checkBatchDetailInfo = this.baseMapper.selectByCid(checkBatchDetailId);

        System.err.println(checkBatchDetailInfo);

        if (checkBatchDetailInfo == null) {
            throw new BusinessException("选择对账明细记录已经不存在，请刷新画面重新处理。");
        } else {
            System.err.println(processState);
            if (processState != null
                    && processState != 0
                    && processState != ProcessStateCheckBillEnum.WCL.getIndex()) {
                // 状态不是未处理的时候，提示画面
                throw new RuntimeException("选择对账明细记录已经被处理过，请勿重复处理。");
            }
        }

        CwCheckBatchDetail checkBatchDetailForUpd = new CwCheckBatchDetail();
        // 对账明细记录ID
        checkBatchDetailForUpd.setId(checkBatchDetailId);
        // 差错处理结果：1：未处理, 2：要结算，3：不结算，4：已处理
        // (对于入金，选择1，或者2来提示处理结果，出金，线下处理账款，上来标记已处理状态, 没有差错的时候为空)
        //  增加金融服务的考虑，不只看入金，只有商户结算金额存在的时候，才会有结算的状态，不结算的时候，只更新处理结果
        // Enum: ProcessStateCheckBillEnum
        checkBatchDetailForUpd.setProcessState(4);

        checkBatchDetailForUpd.setUpdateUserid(tokenService.getLoginUser().getUserid());
        checkBatchDetailForUpd.setUpdateTime(new Date());

        // 更新处理
        this.cwCheckBatchDetailService.updateById(checkBatchDetailForUpd);

        log.info("processCheckDifResult对账差异的差错处理 End.");
    }

    @Override
    public CwCheckBatch getCwCheckBatchByBillDay(String date) {
        return this.baseMapper.getCwCheckBatchByBillDay(date);
    }

    @Override
    public CheckBatchConfirmResponseDto checkBatchConfirm(CheckBatchConfirmRequestDto checkBatchConfirmRequestDto) {

        // 对账确认时间
        Date confirmDate = new Date();

        // 查询批次信息
        CwCheckBatchEntity batchInfo = this.selectCheckBatchByBatchNo(checkBatchConfirmRequestDto.getBatchNo());

        if (batchInfo == null) {
            log.warning("----未查到该批次信息，对账确认失败.");
            throw new BusinessException("未查到该批次信息，对账确认失败。");
        } else {
            // 批次状态
            // 取消或者未完成的时候
            if (batchInfo.getCompleteState() == BusinessCompleteStateEnum.QUXIAO.getIndex()) {
                log.warning("----该批次信息已取消，对账确认失败.");
                throw new BusinessException("该批次信息已取消，对账确认失败。");
            } else if (batchInfo.getCompleteState() == BusinessCompleteStateEnum.WEIWANCHENG.getIndex()) {
                log.warning("----该批次信息未完成，对账确认失败.");
                throw new BusinessException("该批次信息未完成，对账确认失败。");
            } else {
                if (batchInfo.getConfirmDate() != null) {
                    log.warning("----该批次信息已是对账确认状态，对账确认失败.");
                    throw new BusinessException("该批次信息已是对账确认状态，对账确认失败。");
                }
            }
        }

        // 查询该批次对应的明细数据
        CwCheckBatchDetail batchDetailOption = new CwCheckBatchDetail();
        batchDetailOption.setBatchNo(checkBatchConfirmRequestDto.getBatchNo());
        batchDetailOption.setDelFlg(0);
        List<CwCheckBatchDetailEntity> batchDetailList = cwCheckBatchDetailService.selectList(batchDetailOption);

        if (batchDetailList == null || batchDetailList.size() == 0) {
            throw new BusinessException("该批次无对账明细数据。");
//			return null;
        } else {
            // 检查每条明细的差错处理状态
            for (CwCheckBatchDetailEntity batchDetailItem : batchDetailList) {
                if (batchDetailItem.getHasDiff()
                        && batchDetailItem.getProcessState() == ProcessStateCheckBillEnum.WCL.getIndex()) {
                    // 有差错未处理的时候
                    throw new BusinessException("存在未处理的差错，对账确认失败。");
                }
            }
        }


        // 循环对账明细，将无差错的或者要结算的入金账单，插入到待结算表中，等待结算审核（线上交易部分）
        for (CwCheckBatchDetailEntity batchDetailItem : batchDetailList) {


            // update by fl 20180524 增加金融服务的场景 start
//			// **************** 1、入金，并且无差错，或者差错处理要结算
//			// 目前不考虑金融，入金的支付方式包括如下线上方式：1:微信扫码，2:支付宝扫码，3:微信公众号，4:认证支付
//			if ((PayWayEnum.WXSM.getIndex() == batchDetailItem.getPayWay()
//					|| PayWayEnum.ZFBSM.getIndex() == batchDetailItem.getPayWay()
//					|| PayWayEnum.WXGZH.getIndex() == batchDetailItem.getPayWay()
//					|| PayWayEnum.RZZF.getIndex() == batchDetailItem.getPayWay())
//				&& (!batchDetailItem.getHasDiff()                            // 无差错
//						|| (batchDetailItem.getHasDiff()                     // 有差错，处理状态是要结算
//								&& ProcessStateCheckBillEnum.YJS.getIndex() == batchDetailItem.getProcessState()))) {

            // **************** 1、有商户结算金额，无差错，或者差错处理要结算的
            if (batchDetailItem.getCanClearingAmount() != null                                  // 有商户可结算金额
                    && BigDecimal.ZERO.compareTo(batchDetailItem.getCanClearingAmount()) < 0    // 商户可结算金额 > 0
                    && (!batchDetailItem.getHasDiff()                                           // 无差错
                    || (batchDetailItem.getHasDiff()                                        // 有差错，处理状态是要结算
                    && ProcessStateCheckBillEnum.YJS.getIndex() == batchDetailItem.getProcessState()))) {
                // update by fl 20180524 增加金融服务的场景 end

                // 查询对应的系统支付订单信息
                // 对账明细中的支付订单号（交易流水号是拉卡拉同平台的号用/拼接的）
                String dispPayOrderNo = batchDetailItem.getPayOrderNo();

                if (StringUtils.isBlank(dispPayOrderNo)) {
                    log.warning("--------当前处理的批次明细中没有支付订单号，该条明细处理跳过。");
                    continue;
                }

                // 拉卡拉订单号在左边，平台在右边
                String[] dispOrderNoArray = dispPayOrderNo.split(CHECKDETAILCONNECTSTR);

                if (dispOrderNoArray == null || dispOrderNoArray.length == 0) {
                    log.warning("--------当前处理的批次明细中没有支付订单号，该条明细处理跳过。");
                    continue;
                }

                // 先使用平台支付订单，没有的时候，使用拉卡拉对账的支付订单
                String orderNo =  dispOrderNoArray.length == 1 ? dispOrderNoArray[0] : dispOrderNoArray[1];

                CwPayOrder payOrder = this.cwPayOrderService.selectPayOrderByOrderNo(orderNo);

                // 结算明细
                CwClearing clearingEntity = new CwClearing();
                // 商户信息(商户ID, 商户名称)
                this.setBusinessInfoInClearing(clearingEntity, payOrder);
                // 对账年月日(yyyymmdd)
                clearingEntity.setCheckDay(batchDetailItem.getCheckDay());
                // 结算的对账批次ID
                clearingEntity.setCheckBatchId(batchDetailItem.getBatchId());
                // 结算的对账批次号（yyyymmdd001）
                clearingEntity.setCheckBatchNo(batchDetailItem.getBatchNo());
                // 结算的对账批次明细ID
                clearingEntity.setCheckBatchDetailId(batchDetailItem.getId());

                // 交易流水号，支付订单的支付订单号
                clearingEntity.setPayOrderNo(orderNo);

                // 渠道名称(拉卡拉账单类型) 1:代付（提现），2：快捷，3：微信，4：支付宝
                clearingEntity.setBillType(batchInfo.getBillType());

                // 对账确认时间
                clearingEntity.setCheckConfirmDate(confirmDate);

                if (payOrder.getCanClearingAmount() != null) {
                    // 结算金额（对账的订单金额）
                    // update by fl 20180524 增加金融服务的场景 start
                    //clearingEntity.setAmount(payOrder.getAmount());
                    clearingEntity.setAmount(payOrder.getCanClearingAmount());
                    // update by fl 20180524 增加金融服务的场景 end
                }

                // 交易日期（对账明细里面的交易日期，也即渠道支付日期）
                clearingEntity.setTradeDateZf(payOrder.getTradeDateZf());

                // 结算确认状态（未确认）
                clearingEntity.setClearingConfirmState(ClearingConfirmStateEnum.WQR.getIndex());

                // 结算确认人    (结算时设置)
                // 结算确认时间 (结算时设置)

                // 创建人/时间， 更新人/时间
                clearingEntity.setCreateUserid(tokenService.getLoginUser().getUserid());
                clearingEntity.setCreateTime(new Date());
                clearingEntity.setUpdateUserid(tokenService.getLoginUser().getUserid());
                clearingEntity.setUpdateTime(new Date());

                // 创建结算明细记录
                clearingService.save(clearingEntity);

                //  **************** 2、更新需要结算的支付订单的状态
                CwPayOrder payOrderForUpdate = new CwPayOrder();
                payOrderForUpdate.setId(payOrder.getId());
                // 对账状态：2=已对账----->   3=待结算
                payOrderForUpdate.setDzState(DzStateEnum.DJS.getIndex());
                payOrderForUpdate.setUpdateUserid(tokenService.getLoginUser().getUserid());
                payOrderForUpdate.setUpdateTime(new Date());
                // 更新支付订单状态
                this.cwPayOrderService.updateById(payOrderForUpdate);

            } else {
                //logger.info("------------非入金数据，不用结算。");
                log.info("------------没有商户可结算金额，不用结算。");
            }
        }

        // **************** 3、更新对账批次明细和对账批次表对账确认时间
        // 对账批次明细
        this.cwCheckBatchDetailMapper.updateConfirmDate(checkBatchConfirmRequestDto);

        // 对账批次
        CwCheckBatch batchInfoForUpdate = new CwCheckBatch();
        batchInfoForUpdate.setId(batchInfo.getId());
        batchInfoForUpdate.setConfirmDate(confirmDate);
        batchInfoForUpdate.setUpdateUserid(tokenService.getLoginUser().getUserid());
        batchInfoForUpdate.setUpdateTime(new Date());

        this.baseMapper.updateById(batchInfoForUpdate);

        return null;
    }


    /*
     * 根据对账批次号（不是ID）查询对账批次信息
     */
    public CwCheckBatchEntity selectCheckBatchByBatchNo(String batchNo) {

        CwCheckBatchEntity selectOption = new CwCheckBatchEntity();
        selectOption.setBatchNo(batchNo);
        selectOption.setDelFlg(false);

        CwCheckBatchEntity result =  this.baseMapper.getOne(selectOption);

        return result;
    }

    /**
     * 对账确认的时候，取得并设置对应流水的商户信息
     * @param clearingEntity
     * @param payOrder
     */
    private void setBusinessInfoInClearing(CwClearing clearingEntity, CwPayOrder payOrder) {

        log.info("setBusinessInfoInClearing商户信息设置处理 Start...");

        if (payOrder == null) return;

        //  查询该笔支付订单对应的业务订单，然后根据业务订单确定商户
        CwPayOrderDetail selectOption = new CwPayOrderDetail();
        // 支付订单ID
        selectOption.setPayOrderId(payOrder.getId());
        selectOption.setDelFlg(0);
        List<CwPayOrderDetail> orderDetailList = this.cwPayOrderDetailService.selectList(selectOption);

        if (orderDetailList == null || orderDetailList.size() == 0)  {
            log.info("----支付订单明细数据查询无.");
            log.info("setBusinessInfoInClearing商户信息设置处理 End.");
            return;
        }

        for (CwPayOrderDetail orderDetail : orderDetailList) {
            // 目前业务中，入金的业务包括企业充值和企业收款（TODO暂不考虑金融相关业务）
            if (OperationTypeEnum.CZ.getIndex() == orderDetail.getBusinessOrderType()
                    || OperationTypeEnum.SK.getIndex() == orderDetail.getBusinessOrderType()) {
                // 商户ID设置
                clearingEntity.setBusinessId(orderDetail.getBusinessId());
                // 商户名称设置
                clearingEntity.setBusinessName(orderDetail.getBusinessName());

                log.info("----商户信息设置成功。");

                // 暂时不考虑一笔流水里面对应多个商家的情况
                break;
            }
        }

        log.info("setBusinessInfoInClearing商户信息设置处理 End.");

    }
}




